using TrackSystem.Entities.Extensions;
using TrackSystem.IO.Alarm;
using TrackSystem.IO.Data;
using TrackSystem.IO.Models;
using TrackSystem.IO.Utils;

namespace TrackSystem.IO.Protocol
{
    /// <summary>
    /// 网络相机镜头通信协议（TCP）
    /// 0-zoom wide
    /// 1-zoom Tele
    /// 2-zoom stop
    /// 3-focus far
    /// 4-focus near
    /// 5-focus stop
    /// 6-focus mode   focus mode 1-auto；2-manual；3-semi-automatic
    /// 7-iris mode    iris mode 1-manual,2-auto,3-iris first,4-shutter first,5-gain first
    /// 8-iris up
    /// 9-iris down
    /// </summary>
    public class NetCameraTCPProtocl : ProtocolBase
    {
        private int startTicks;
        private int repeatTimes;    //写入操作重复次数

        private readonly int roLength;
        private readonly int rwLength;
        private bool bSendW;     // 发送标志

        private string camIp;
        private int camPort;
        private string camAdmin;
        private string camPassword;
        private HCNetCamControl camController;
        bool isLogin;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name"></param>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="admin"></param>
        /// <param name="password"></param>
        /// <param name="roLength"></param>
        /// <param name="rwLength"></param>
        public NetCameraTCPProtocl(string name, string ip, int port,string admin,string password,int roLength,int rwLength)
            : base()
        {
            Name = name;
            camIp = ip;
            camPort = port;
            camAdmin = admin;
            camPassword = password;
            this.roLength = roLength; //需要定义
            this.rwLength = rwLength;
            NeedInit = true;
            isLogin = false;
        }

        /// <summary>
        /// 生成读取寄存器的通讯帧
        /// </summary>
        /// <returns></returns>
        public override byte[] GenerateReadFrame(out int NeedRecvLen)
        {
            startTicks = Environment.TickCount;
            if (!isLogin)
            {
                Fail_R++;
            }
            else {
               Succ_R++;
            }
            if (NeedInit && !isLogin && Fail_R > 900 && Fail_R < 1200) { // 延迟90秒后开始尝试登录,120秒后不再尝试（转为发送指令尝试）
                camController = new HCNetCamControl(camIp,camPort,camAdmin,camPassword);
                isLogin = camController.login();
                if (isLogin)
                {
                    NeedInit = false;
                    Fail_R = 0;
                    for (int i = 0; i < rwLength; i++)
                    {
                        RegFactory.Instance.SetVal(RegNameList[i], 0);
                    }
                    //List<int> indexFirst = new List<int> {11 , 12, 13, 14};
                    //List<double> indexValue = new List<double> {0.0,0.0,0.0,0.0};
                    //camController.setShowStringInfo(indexFirst, indexValue);
                }
            }
            if (Fail_R >= 10) {
                Succ_R = 0;
            }
            NeedRecvLen = 0;
            return null;
        }


        /// <summary>
        /// 根据收到的内容进行处理
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public override bool ProcessReadFrame(byte[] buffer)
        {
            Rx_r = buffer;
            Lapse = Environment.TickCount - startTicks;
            return true;
        }

        /// <summary>
        /// 生成写入寄存器的通讯帧
        /// </summary>
        /// <param name="NeedRecvLen"></param>
        /// <returns></returns>
        public override byte[] GenerateWriteFrame(out int NeedRecvLen)
        {
            // 待写入的数据队列非空 
            if (writeQueue.Count() > 0)
            {
                repeatTimes = 3;    // 写入的重复次数更新为3次
            }
            // 生成写入数据帧
            List<int> addr =new List<int> { };
            List<double> setValue =new List<double> { };
            if (WriteFlag && repeatTimes-- > 0)
            {
                bSendW = false;
                startTicks = Environment.TickCount;
                while (writeQueue.TryDequeue(out AddressAndVal data))
                {
                    if (data.Address == 0 && data.Value == 1)
                    {
                        bSendW = camController.setPTZPara(12, 0); // zoom wide
                    }
                    else if (data.Address == 1 && data.Value == 1)
                    {
                        bSendW = camController.setPTZPara(11, 0); // zoom tele
                    }
                    else if (data.Address == 2 && data.Value == 1)
                    {
                        bSendW = camController.setPTZPara(11, 1); // zoom stop
                    }
                    else if (data.Address == 3 && data.Value == 1)
                    {
                        bSendW = camController.setPTZPara(14, 0); // focus far
                    }
                    else if (data.Address == 4 && data.Value == 1)
                    {
                        bSendW = camController.setPTZPara(13, 0); // focus near
                    }
                    else if (data.Address == 5 && data.Value == 1)
                    {
                        bSendW = camController.setPTZPara(13, 1); // focus stop
                    }
                    else if (data.Address == 6 && (data.Value == 1 || data.Value == 2 || data.Value == 3))
                    {
                        bSendW = camController.setFocusMode((int)data.Value - 1); // focus mode 1-auto；2-manual；3-semi-automatic
                    }
                    else if (data.Address == 7 && (data.Value >= 1 && data.Value <= 5))
                    {
                        bSendW = camController.setExporeMode((int)data.Value - 1); // iris mode 1-manual,2-auto,3-iris first,4-shutter first,5-gain first
                    }
                    else if (data.Address == 8 && data.Value == 1)
                    {
                        bSendW = camController.setPTZPara(15, 0); // iris up
                    }
                    else if (data.Address == 9 && data.Value == 1)
                    {
                        bSendW = camController.setPTZPara(16, 0); // iris down
                    }
                    else if (data.Address == 10 && data.Value == 1)
                    {
                        bSendW = camController.logout(); // manual logout
                        if (bSendW) {
                            isLogin = false;
                            NeedInit = true;
                            Succ_R = 0;
                        }
                    }
                    else if (data.Address >= 11 && data.Address < 18) // 叠加字符
                    {
                        if (addr.Contains(data.Address))
                        {
                            var index = addr.IndexOf(data.Address);
                            setValue[index] = data.Value;
                        }
                        else {
                            addr.Add(data.Address);
                            setValue.Add(data.Value);
                        }
                    } else if (data.Address >= 19 && data.Address < 26) {  // OSD font-size
                        bSendW = camController.setOSD(data.Address, data.Value);
                    }
                    if (bSendW) {
                        RegFactory.Instance.SetVal(RegNameList[data.Address], data.Value);
                    }
                }
                if (addr.Count > 0) {
                    bSendW=camController.setShowStringInfo(addr, setValue); // set OSD String
                }
                if (bSendW)
                {
                    WriteFlag = false;
                    Succ_W++;
                    Fail_W = 0;
                }
                else {
                    Fail_W++;
                }
                Lapse = Environment.TickCount - startTicks;
                // 上次没有收到正确的返回帧
                NeedRecvLen = 0;
                return null;
            }

            // 如果写入次数超过三次未成功，则将队列清空
            if (repeatTimes <= 0)
            {
                AlarmFactory.Instance.Insert("Write data error, more than three attempts",
                    AlarmCategory.COMM, Name, 0);

                // 标志位复位 重启下一个批次的读写任务
                WriteFlag = false;
            }
            NeedRecvLen = 0;
            return null;
        }

        /// <summary>
        /// 修改寄存器的值
        /// </summary>
        /// <param name="Index"></param>
        /// <param name="Value"></param>
        public override void PushRegValue(int Index, double Value)
        {
            Index -= roLength;  //寄存器存储顺序从0开始，先是只读存储器，后面是读写存储器

            if (Index >= 0 && (Index < rwLength))
            {
                if (Index==18) {
                    writeQueue.Clear();// 清空队列
                }
                else if (isLogin)
                {
                    writeQueue.Enqueue(new AddressAndVal(Index, Value));
                    WriteFlag = true;
                }
                else if(!NeedInit) {
                    camController = new HCNetCamControl(camIp, camPort, camAdmin, camPassword);
                    isLogin = camController.login();
                    if (isLogin)
                    {
                        NeedInit = false;
                        Fail_R = 0;
                        for (int i = 0; i < rwLength; i++)
                        {
                            RegFactory.Instance.SetVal(RegNameList[i], 0);
                        }
                    }
                    else
                    {
                        WriteFlag = false;
                        Fail_W++;
                    }
                }
            }
        }
    }
}

